﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using Ganosoft.Aspect;
using Ganosoft.Container;
using Ganosoft.Container.Utils;
using Newtonsoft.Json;

namespace GanoESB.Business
{
    /// <summary>
    /// 服务总线
    /// </summary>
    public class ServiceBus : IServiceBus
    {
        [Bean]
        protected ILogService logService;
        [Bean]
        protected Server server;
        [Bean]
        protected IDeployer deployer;
        private IServiceFinder callback;

        private Dictionary<string, ComponentRuntime> compList;
        private Dictionary<ServiceDescriptor, ServiceItem> descrList;
        private Dictionary<ServiceDescriptor, ServiceController> controllerList;
        private Dictionary<string, MessageHandler> handlerList;

	    public ISecurityChecker SecurityChecker;

        public ServiceBus()
        {
            compList = new Dictionary<string, ComponentRuntime>();
            descrList = new Dictionary<ServiceDescriptor, ServiceItem>();
            controllerList = new Dictionary<ServiceDescriptor, ServiceController>();            
            handlerList = new Dictionary<string, MessageHandler>();
        }

        public IServiceFinder Callback
        {
            get 
            {
                if (callback == null)
                {
                    callback = new ServiceFinder();
                    AspectContainer.Instance.Inject(callback);
                }
                return callback;
            }
        }

        public void Start()
        {
            deployer.StartScan(this);
        }

        public void Stop()
        {
            deployer.StopScan();
            foreach (ComponentRuntime ctx in compList.Values)
            {
                //TODO: 移除相关服务
                ctx.Stop();
            }
        }

        public void RegisterMessage(string scope, Type intfType, ServiceController sc)
        {
            ComponentRuntime compCtx = GetComponentContext(scope);
            Dictionary<string, Type> types = compCtx.GetMessageTypes(intfType);

            MethodInfo[] methods = intfType.GetMethods();
            foreach (MethodInfo m in methods)
            {
                string messageName = m.Name + "Message";
                if (types.ContainsKey(messageName))
                {
                    string fullname = scope + "_" + messageName;
                    handlerList[fullname] = new MessageHandler(types[messageName], m, sc);
                }
            }
        }

        public MessageResponse Execute(string secretKey, MessageRequest req)
        {
            if (!handlerList.ContainsKey(req.MessageName))
                throw new Exception("Don't found message handler.");

            MessageHandler handler = handlerList[req.MessageName];
            IMessage message = (IMessage)JsonConvert.DeserializeObject(req.MessageJson, handler.MessageType);
            if (SecurityChecker != null)
            {
                if (!SecurityChecker.Check(secretKey, message))
                    throw new Exception("Security check fail.");
            }

            MessageResponse resp = new MessageResponse();
            object obj = handler.Handle(message);
            resp.Result = JsonConvert.SerializeObject(obj);

            return resp;
        }

        /// <summary>
        /// 注册组件
        /// </summary>
        /// <param name="descr"></param>
        public void RegisterComponent(ComponentDescriptor descr)
        {
            logService.Info(this.GetType(), "注册组件" + descr.ComponentName);
            ComponentRuntime ctx = new ComponentRuntime(descr, this);
            compList[descr.ComponentName] = ctx;
            ctx.Start();
        }

        public void UnregisterComponent(string file)
        {
            ComponentRuntime ctx = null;
            foreach (ComponentRuntime cc in compList.Values)
            {
                if (cc.DeploymentFile == file)
                {
                    ctx = cc;
                    break;
                }
            }

            if (ctx != null)
            {               
                ctx.Stop();
            }
        }
        
        #region IServiceBus 成员

        public void RegisterService(ServiceDescriptor[] descrs)
        {
            for (int i = 0; i < descrs.Length; i++)
            { 
                ServiceController sc = new ServiceController(descrs[i], this);

                controllerList[descrs[i]] = sc;
                descrList[descrs[i]] = sc.ServiceItem;

                sc.Start();
            }
        }

        public void UnregisterService(ServiceDescriptor descr)
        {
            descrList.Remove(descr);
            controllerList.Remove(descr);

            ServiceController sc = controllerList[descr];
            sc.Stop();
        }

        public void StartService(string serviceName)
        {
            ServiceController sc = null;
            foreach (ServiceDescriptor descr in controllerList.Keys)
            {
                if (descr.ServiceName == serviceName)
                {
                    sc = controllerList[descr];
                    break;
                }
            }
            if (sc != null)
                sc.Start();
        }

        public void StopService(string serviceName)
        {
            ServiceController sc = null;
            foreach (ServiceDescriptor descr in controllerList.Keys)
            {
                if (descr.ServiceName == serviceName)
                {
                    sc = controllerList[descr];
                    break;
                }
            }
            if (sc != null)
                sc.Stop();
        }

        public ServiceItem FindServiceByType(string typeName)
        {
            ServiceItem ret = null;
            foreach (ServiceDescriptor descr in descrList.Keys)
            {
                if (descr.ServiceInterface.StartsWith(typeName))
                {
                    ret = descrList[descr];
                    break;
                }
            }
            return ret;
        }

        public ServiceDetail[] GetServiceDetails()
        {
            List<ServiceDetail> list = new List<ServiceDetail>();
            foreach (ServiceController sc in controllerList.Values)
            {
                list.Add(sc.ServiceDetail);
            }
            return list.ToArray();
        }

        public ServiceDetail GetServiceDetail(string serviceName)
        {
            ServiceController sc = null;
            foreach (ServiceDescriptor descr in controllerList.Keys)
            {
                if (descr.ServiceName == serviceName)
                {
                    sc = controllerList[descr];
                    break;
                }
            }
            if (sc != null)
                return sc.ServiceDetail;

            return null;
        }

        public ServiceCall[] GetServiceCalls(string serviceName)
        {
            ServiceController sc = null;
            foreach (ServiceDescriptor descr in controllerList.Keys)
            {
                if (descr.ServiceName == serviceName)
                {
                    sc = controllerList[descr];
                    break;
                }
            }
            if (sc != null)
                return sc.ServiceCalls;

            return null;
        }

        #endregion

        internal ComponentRuntime GetComponentContext(string name)
        {
            if (compList.ContainsKey(name))
                return compList[name];

            return null;
        }
    }
}
